package com.wangshb.upms.core.exception;

import com.wangshb.upms.core.common.GpResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;


@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler implements ResponseBodyAdvice<Object> {

    /**
     * 400 异常处理
     * @param e
     * @return
     */
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    @ResponseBody
    @ExceptionHandler({HttpMessageNotReadableException.class, MissingServletRequestParameterException.class})
    public GpResponse handleHttpMessageNotReadableException(Exception e){
        log.error(e.getMessage(), e);
        return GpResponse.fail("请求参数类型不匹配",e.getMessage());
    }


    /**
     * businessException异常处理
     * @param e
     * @return
     */
    @ExceptionHandler(value = BusinessException.class)
    @ResponseBody
    public GpResponse handleBusinessException(BusinessException e){
        log.error(e.getMessage(), e);
        return GpResponse.fail(e.getMessage(), null, e.getErrorCode());
    }



    /**
     * exception异常处理
     * @param e
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public GpResponse handleException(Exception e){
        log.error(e.getMessage(), e);
        return GpResponse.fail("系统异常",e.getMessage());
    }

    /**
     *
     */
    @ExceptionHandler(value = OptimisticLockException.class)
    @ResponseBody
    public GpResponse handleOptimisticlockException(OptimisticLockException e){
        log.error(e.getMessage(), e);
        return GpResponse.fail("数据已被其他用户修改，请重试", e.getMessage());
    }


    /**
     * 处理校验
     * @param e
     * @return
     */
    @ExceptionHandler(value = { MethodArgumentNotValidException.class })
    @ResponseBody
    public GpResponse handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        List<String> errorInformation = e.getBindingResult().getAllErrors()
                .stream()
                .map(ObjectError::getDefaultMessage)
                .collect(Collectors.toList());
        return GpResponse.fail(StringUtils.join(errorInformation.toArray(), ";"), errorInformation);
    }


    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        //注解@Slf4j所带，属于非常推荐的lombok项目，可以去看看我的idea插件去了解一下
        if (body != null) {

            if (body instanceof Exception ) {
                log.error("", (Exception)body);
            }
            log.info("请求返回数据类型class={}", body.getClass().getName());
        }
        GpResponse result;
        //兼容原来的接口返回
        if(body instanceof GpResponse){
            result=(GpResponse)body;
        }else{
            result=new GpResponse();
            result.setCode(20000);
            result.setMsg("操作成功");
            result.setData(body);
        }
        return result;
    }
}
